package com.own.business.login.core.core;

import com.own.component.common.hook.business.LoginSecurityHook;
import com.own.component.common.hook.business.LoginSecurityHookEntity;
import com.own.component.common.util.list.MapUtil;
import com.own.constant.ConstantAccount;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

/**
 * LoginSecuritySpringHook
 *
 * @author chenxueli
 * @date 2023-02-13 14:36:00
 */
@Slf4j
@Component
@SuppressWarnings("all")
public class LoginSecuritySpringHook implements ApplicationContextAware, ApplicationListener<ApplicationEvent> {

    /**
     * 默认的客户端key（单个服务器唯一就行）
     */
    private static final String DEFAULT_KEY = UUID.randomUUID().toString();
    private static ApplicationContext applicationContext;
    /**
     * 所有的处理钩子
     */
    private Map<String, List<LoginSecurityHook>> LOGIN_SECURITY_HOOK_MAP = new HashMap<>();
    private List<LoginSecurityHook> COMMON_LOGIN_SECURITY_HOOK_MAP = new ArrayList<>();

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        LoginSecuritySpringHook.applicationContext = context;
    }

    @Override
    public void onApplicationEvent(ApplicationEvent event) {
        if (event instanceof ApplicationReadyEvent) {
            LOGIN_SECURITY_HOOK_MAP.put(DEFAULT_KEY, new ArrayList<>());
            applicationContext.getBeansOfType(LoginSecurityHook.class).forEach((key, hook) -> {
                var clients = hook.client();
                if (clients == null) {
                    COMMON_LOGIN_SECURITY_HOOK_MAP.add(hook);
                } else {
                    MapUtil.group(Arrays.asList(hook.client()), hook, LOGIN_SECURITY_HOOK_MAP);
                }
                LOGIN_SECURITY_HOOK_MAP.get(DEFAULT_KEY).add(hook);
                // debug日志输出
                log.debug("登录安全验证信息===>【{}】完成注册", key);
            });
        }
    }

    /**
     * 检查登录安全（默认为普通用户）
     *
     * @param userId  用户ID
     * @param request 请求信息
     * @return 是否通过
     */
    public LoginSecurityHookEntity checkNormal(Long userId, HttpServletRequest request) {
        return check(DEFAULT_KEY, userId, ConstantAccount.TypeEnum.NORMAL, request);
    }

    /**
     * 检查登录安全（默认为管理员用户）
     *
     * @param userId  用户ID
     * @param request 请求信息
     * @return 是否通过
     */
    public LoginSecurityHookEntity checkNormalAdmin(Long userId, HttpServletRequest request) {
        return check(DEFAULT_KEY, userId, ConstantAccount.TypeEnum.ADMIN, request);
    }

    /**
     * 检查登录安全
     *
     * @param userId      用户ID
     * @param accountType 账号类型 1=普通账号 2=管理员
     * @param request     请求信息
     * @return 是否通过
     */
    public LoginSecurityHookEntity check(Long userId, ConstantAccount.TypeEnum accountType, HttpServletRequest request) {
        return check(DEFAULT_KEY, userId, accountType, request);
    }

    /**
     * 检查登录安全
     *
     * @param client      客户端信息
     * @param userId      用户ID
     * @param accountType 账号类型 1=普通账号 2=管理员
     * @param request     请求信息
     * @return 是否通过
     */
    public LoginSecurityHookEntity check(String client, Long userId, ConstantAccount.TypeEnum accountType, HttpServletRequest request) {
        var list = LOGIN_SECURITY_HOOK_MAP.getOrDefault(client, Collections.emptyList());
        for (var hook : list) {
            var entity = hook.check(client, userId, accountType, request);
            if (!entity.flag()) {
                return entity;
            }
        }
        // 验证通用的
        for (var hook : COMMON_LOGIN_SECURITY_HOOK_MAP) {
            var entity = hook.check(client, userId, accountType, request);
            if (!entity.flag()) {
                return entity;
            }
        }
        return LoginSecurityHookEntity.SUCCESS;
    }

}
